#include <gion/utility.hpp>
#include <gion/auto_handle.hpp>

#include <cassert>
#include <cstddef>

using gion::auto_handle;

std::size_t x_n = 0;
std::size_t x_id = 0;

int x_open()
{
  ++x_n;
  ++x_id;
  return x_id;
}

void x_close(int x)
{
  --x_n;
}

struct x_traits
{
  typedef int handle_type;
  static bool equal(handle_type lhs, handle_type rhs)
  {
    return lhs == rhs;
  }

  static void deallocate(handle_type handle)
  {
    x_close(handle);
  }
};

typedef auto_handle<x_traits> x_handle;

void referencer(x_handle::const_reference x)
{
  assert(empty(x) == false);
}

void basic_tests()
{
  assert(x_n == 0);
  x_handle bar(x_open());
  assert(empty(bar) == false);
  assert(bar.get() == 1);
  assert(x_n == 1);

  int h = bar.release();
  assert(x_n == 1);
  assert(empty(bar) == true);

  bar.reset(h);
  assert(x_n == 1);
  assert(empty(bar) == false);

  x_handle::const_reference x = get_ref(bar);
  assert(x_n == 1);
  assert(empty(bar) == false);
  referencer(x);
  assert(x_n == 1);
  assert(empty(bar) == false);
  referencer(get_ref(bar));  
  assert(x_n == 1);
  assert(empty(bar) == false);
  
  bar.reset();
  assert(x_n == 0);
  assert(empty(bar) == true);
}

x_handle producer()
{
  return x_handle(x_open());
}

void consumer(x_handle bar)
{
  assert(empty(bar) == false);
}
void ownership_transfer_tests()
{
  assert(x_n == 0);
  {
    consumer(producer());
    assert(x_n == 0);
    x_handle bar;
    bar = producer();
    assert(empty(bar) == false);
    assert(x_n == 1);
    x_handle baz(producer());
    assert(empty(baz) == false);
    assert(x_n == 2);
    bar = baz;
    assert(empty(baz) == true);
    assert(empty(bar) == false);
    assert(x_n == 1);
    producer();
    assert(x_n == 1);
  }
  assert(x_n == 0);
}

int main()
{
  basic_tests();
  ownership_transfer_tests();
  return 0;
}
